// OPTLNK - Copyright (c) SLR Systems 1994

module optlnk;

	INCLUDE MACROS
	INCLUDE	INITCODE
	INCLUDE	IO_STRUC
	INCLUDE	WIN32DEF
	INCLUDE	WINMACS

	PUBLIC	OPTLINK,CLEAN_UP,RETT,OPTLINK_RESTART,main

	EXTERNDEF	DOSCWAIT:PROC


	.DATA

	EXTERNDEF	ASCIZ:BYTE,XOUTBUF:BYTE,CTRL_C_FLAG:BYTE,TEMP_RECORD:BYTE,TYPE_COLLISION_TID:BYTE

	EXTERNDEF	MYSTACK:DWORD,ALLOCATED_BLOCKS:DWORD,__psp:DWORD,ERR_COUNT:DWORD,OUTFILE_GINDEX:DWORD
	EXTERNDEF	ALLOCS_TABLES:DWORD,CVPACK_PID:DWORD,EXE_DEVICE:DWORD,MAP_DEVICE:DWORD,MAPFILE_GINDEX:DWORD
	EXTERNDEF	NUMBLKS:DWORD,STARTING_ESP:DWORD,PMODE:DWORD,ALLOCATED_IO_BLOCKS:DWORD,TYPE_COLLISION_MAX:DWORD
	EXTERNDEF	OBJ_DEVICE:DWORD,IND_DEVICE:DWORD,PARALLEL_TABLES:DWORD,WORKFILE:DWORD,CVPACK_ADDR:DWORD
	EXTERNDEF	OLD_DTA:DWORD,MAP_THREAD_HANDLE:DWORD,HOST_ESP:DWORD

	EXTERNDEF	MYO_STUFF:MYO_STRUCT,FILE_LIST_GARRAY:STD_PTR_S,OUTFILE_GARRAY:STD_PTR_S
	EXTERNDEF	LOCKED_STUFF:LKD_ALLOC_STRUCT,MYI_STUFF:MYI_STRUCT,MAP_THREAD_TERM_SEM:QWORD


	.CODE	ROOT_TEXT

	EXTERNDEF	LNKINIT:PROC,PASS1_STUFF:PROC,WRITE_MAP:PROC,MIDDLE_STUFF:PROC,PASS2_STUFF:PROC,EXIT:PROC
	EXTERNDEF	MOVE_FN_TO_ASCIZ:PROC,CLOSE_HANDLE:PROC,CBTA16:PROC,DO_DOSSEMWAIT_SSAX:PROC,CBTA32:PROC
	EXTERNDEF	DO_DOSDELETE:PROC,LOUTALL_CON:PROC,CAPTURE_EAX:PROC,DOT:PROC,ERR_RET:PROC,SAY_VERBOSE:PROC
	EXTERNDEF	ABORT:PROC,CVPACK_RUNNER:PROC,RELEASE_MINIDATA:PROC,FLUSH_PHYS_TABLE:PROC,FLUSH_TRUNC_CLOSE:PROC
	EXTERNDEF	RELEASE_ESBX:PROC,HEXWOUT:PROC,RELEASE_BLOCK:PROC,SAY_CVPACK:PROC,ERR_ABORT:PROC,XCNOTIFY:PROC
	EXTERNDEF	CLOSE_LIB_FILES:PROC,END_OF_INDIRECT:PROC,RELEASE_PARALLEL_ARRAY:PROC,FLUSH_PHYS_IO_TEMP:PROC

	EXTERNDEF	ALLOCS_TABLES_LEN:ABS,DGROUP_STEPPED_ERR:ABS,FATAL_RESTART_ERR:ABS,PARALLEL_TABLES_LEN:ABS


void OPTLINK_RESTART()
{
    ERR_ABORT(FATAL_RESTART_ERR);
}

int main()
{
    INITCODE0

    LNKINIT();

    // ok, command lines all read, ready to go...
    // so, start at head of obj_list and process obj_files

    //printf("PASS1\n");
    PASS1_STUFF()		// reads objs and libs

    //printf("MIDDLE\n");
    MIDDLE_STUFF()		// org segs and publics, etc

    //printf("PASS2\n");
    PASS2_STUFF() 		// fixup and relocate

    // need to wait for any output threads to finish...

    //printf("ENDING'

    version (fgh_mapthread)
    {
	// WAIT FOR MAP THREAD TO FINISH
	if (!HOST_THREADED)
	{
	    if (!MAP_THREAD_HANDLE)
		goto L7;
	    debug SAY_VERBOSE("Waiting for .MAP thread");

	    WaitForSingleObject(EAX, -1);

	    auto EAX = MAP_THREAD_HANDLE;
	    MAP_THREAD_HANDLE = 0;
	    CLOSE_HANDLE(EAX);
	}
    }
    if (MAPFILE_GINDEX)	// flush last buffer of map file
    {
	debug SAY_VERBOSE("Flushing .map");

	MAP_FLUSHED = -1;
	FLUSH_TRUNC_CLOSE(MAP_DEVICE);
    }
L7:
    NO_CANCEL_FLAG = -1
    ABORT()
    return 0;
}


void CLEAN_UP()
{
    PUSHM	EDI,ESI,EBX

    if (CLEAN_UP_IN_PROGRESS)
    {   CLEAN_UP_ABORT();
	return;
    }
    CLEAN_UP_IN_PROGRESS = -1

    version (fgh_win32dll)
    {
	// CLOSE ANY OPEN FILES
	EAX = 0;
	XCHG(&MYI_STUFF.MYI_HANDLE,&EAX);	// only mainstream input file
	NZ_CLOSE_HANDLE();

	CLOSE_LIB_FILES();	// CLOSES AND RELEASES IF ANY...

	EBX = &MYO_STUFF;
	while (ECX--)
	{
	    EAX = 0;
	    XCHG(&[EBX].MYO_STRUCT.MYO_HANDLE, &EAX);
	    NZ_CLOSE_HANDLE();
	    EBX += MYO_STRUCT.sizeof;
	}

	if (BITT LIB_OR_NOT)	// IF IN LIBRARY, DON'T RELEASE MYI_PTR.SEGM
	{
	    EAX = OBJ_DEVICE;
	    IND_DEVICE = EAX;
	    END_OF_INDIRECT(); 	// SAME BUFFER & STUFF...
	}
    }


    version (debug OR fgh_dpmi OR fgh_win32dll)
    {
	auto p = &ALLOCS_TABLES;
	auto n = ALLOCS_TABLES_LEN;
	do
	{
	    ALLOCS_STRUCT* EBX = *p++;
	    debug
	    {
		EDI = &XOUTBUF;
		EAX = [EBX].ALLO_BLK_CNT;
		CBTA32();
		*EDI++ = ' ';
	    }
	    EAX = *p++;
	    debug
	    {
		ESI = EAX;
		ECX = *ESI++ & 0xFF;
		memcpy(EDI, ESI, ECX);
		EDI += ECX;
		ESI += ECX;
		*EDI++ = ' ';
		*EDI++ = ' ';
		EAX = &XOUTBUF;
		ECX = EDI - EAX;
		LOUTALL_CON();
	    }
	    if ([EBX].ALLO_BLK_CNT)
	    {
		EAX = EBX;
		RELEASE_MINIDATA();
	    }
	} while (--n);

	LDK_ALLOC_STRUCT* ESI = &LOCKED_STUFF;
	for (auto EBX = [ESI]._LKD_BLKS_COUNT2; (EBX -= 4) >= 0; )
	{
	    EAX = [ESI+EBX]._LKD_BLKS_OWNED;
	    RELEASE_BLOCK(EAX);
	}
    }

    debug
    {
	EDI = &XOUTBUF;
	CBTA32(ALLOCATED_BLOCKS);
	*EDI++ = ' ';
	*EDI++ = ' ';
	CBTA32(TYPE_COLLISION_MAX);
	*EDI++ = ' ';
	HEXWOUT(TYPE_COLLISION_TID)
	*EDI++ = ' ';
	CBTA32(NUMBLKS);
	*EDI++ = ' ';
	*EDI++ = ' ';

	version (fgh_dpmi)
	{
	    CBTA32(ALLOCATED_IO_BLOCKS)
	    *EDI++ = ' ';
	    *EDI++ = ' ';
	}

	*EDI++ = 0x0D;
	*EDI++ = 0x0A;
	EAX = &XOUTBUF
	ECX = EDI - EAX
	LOUTALL_CON()		;OUTPUT THIS...
    }
    CLEAN_UP_ABORT();
}

void CLEAN_UP_ABORT()
{
    version (fgh_dpmi) FLUSH_PHYS_IO_TEMP();	// may just move to PHYS_TABLE
    //version (fgh_prot) FLUSH_PHYS_TABLE();
}


void RETT()
{
}


void NZ_CLOSE_HANDLE(EAX)
{
    if (EAX)
	CLOSE_HANDLE(EAX);
}
